home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-09-28 | 14.2 KB | 588 lines | [TEXT/KAHL] |
- /****
- * CStandApp.c
- *
- * Methods for a standalone Stand application class.
- *
- * Copyright © 1992 NeoLogic Systems. All rights reserved.
- *
- ****/
-
- #include "NeoTypes.h"
- #include CNeoDatabaseNativeH
-
- #include <Timer.h>
- #include <time.h>
- #include <stdlib.h>
- #include <Traps.h>
- #include <StandardFile.h>
- #ifdef THINK_CPLUS
- #include <console.h>
- #endif
- #if __MWERKS__
- #include <SIOUX.h>
- #endif
- #include <new.h>
-
- #include "CStandApp.h"
- #include CNeoMetaClassH
- #include CNeoIndexIteratorH
- #include "CFiller.h"
- #include CNeoPersistH
-
- #ifndef NeoInherited
- #define NeoInherited CNeoAppAlone
- #endif
-
- #define k30MicroMinutes -(1800000000L)
-
- long gLoopOverhead; // Timer Manager Overhead
-
- static long default_vals[5] = {25000, 25000, 25000, 25000, 25000};
- #ifdef qNeoThreads
- static long default_threads[5] = {1, 2, 2, 2, 1};
- #endif
-
- static Str255 PhaseName[] = { " Insert",
- "Locate Randomly",
- "Locate Serially",
- " Change",
- " Delete"};
- static Str255 ColNames[] = { "\pTotal", "\pSo Far", "\pPer Record", "\pTotal"};
-
- void main(void)
- {
- CStandApp app;
-
- app.run();
- app.exit();
- }
-
- void CStandApp::NewHandler(void)
- {
- gNeoApp->purge(1);
- }
-
- #pragma segment NeoCreate
- CStandApp::CStandApp(void)
- {
- long index;
- long delay = 0;
- TMTask timer;
- SFReply macSFReply;
-
- set_new_handler(NewHandler);
-
- #ifdef qNeoThreads
- fThreadCount = 0;
- for (index = 0; index < kMaxThreads; index++)
- fThreadInfo[index].thread = nil;
- #endif
-
- fDatabase = new CNeoDatabaseAlone(kNeoStandSig, kNeoStandFileType);
- gNeoDatabase = fDatabase;
- fIterator = nil;
-
- ChooseFile(&macSFReply);
- fDatabase->SFSpecify(&macSFReply);
- fDatabase->create();
- fDatabase->open(fsRdWrPerm);
-
- //---------------------------------------------------
- // Get the numbers from the Dialog box, and update
- // the fields with the values of the numbers the
- // user has typed in. Also, if the user has typed
- // in out of range numbers, correct them.
- //---------------------------------------------------
- getTargetTotals();
-
- //---------------------------------------------------
- // I am not sure at this point if you will want to
- // initialize the fields in the fPhaseInfo records
- // other than the totals which come from the users
- // text boxes. If the other fields need
- // initializing, we do it here.
- //---------------------------------------------------
- for (index = kMinPhase; index <= kMaxPhase; index++) {
- fPhaseInfo[index].dirty = FALSE;
- #ifdef __MWERKS__
- fPhaseInfo[index].finished = FALSE;
- #endif
- fPhaseInfo[index].committed = 0;
- fPhaseInfo[index].done = 0;
- fPhaseInfo[index].delta = 0;
- fPhaseInfo[index].soFar = 0;
- #ifdef qNeoThreads
- fPhaseInfo[index].threadCount = default_threads[index];
- #endif
- }
-
- if (fPhaseInfo[kInsert].delta < fPhaseInfo[kInsert].target)
- fPhase = kMinPhase;
- else
- fPhase = kRandomly;
-
- fDirty = FALSE;
- fState = kStart;
- fRefresh = TRUE;
-
- // Just to make sure that we get more random results.
- srand((unsigned int)clock());
-
- // measure Time Manager overhead
- timer.tmAddr = NULL;
- timer.tmCount = 0;
- timer.tmWakeUp = 0;
- timer.tmReserved = 0;
-
- for (index = 0; index < 100; index++) {
- InsTime((QElemPtr)&timer);
- PrimeTime((QElemPtr)&timer, k30MicroMinutes);
- RmvTime((QElemPtr)&timer);
-
- if (timer.tmCount > 0)
- // milliseconds
- delay += -(k30MicroMinutes + timer.tmCount * 1000);
- else
- // negated microseconds
- delay += -(k30MicroMinutes - timer.tmCount);
- }
-
- // compute average overhead
- gLoopOverhead = delay / 100;
-
- #ifdef THINK_CPLUS
- console_options.nrows = 5;
- console_options.ncols = 90;
- NeoBlockMove("\pNeoAccess", console_options.title, 10);
- cshow(stdout);
- cgotoxy(1, 1, stdout);
- #endif
- #if __MWERKS__
- SetSIOUXBufferMode(SIOUXNoBuffering);
- #endif
-
- // Add CFiller class to the metaclass table
- new CNeoMetaClass(kFillerID, kNeoPersistID, kFillerName, CFiller::New);
-
- // Bound the default size of the NeoAccess object cache to be 3/4 of free memory
- CNeoPersist::FCacheSize = ((FreeMem() / 4) * 3);
-
- setState(kStart);
- }
-
- #pragma segment NeoDestroy
- CStandApp::~CStandApp(void)
- {
- #ifdef qNeoThreads
- killThreads();
- #endif
-
- if (gNeoDatabase) {
- gNeoDatabase->close();
- gNeoDatabase = nil;
- }
- }
-
- void CStandApp::setPhase(const short aPhase)
- {
- #ifdef qNeoThreads
- short index;
- short count;
-
- if (aPhase >= kMinPhase &&
- aPhase <= kMaxPhase)
- count = fPhaseInfo[aPhase].threadCount;
- else {
- if (fIterator) {
- delete fIterator;
- fIterator = nil;
- }
- count = 0;
- }
-
- for (index = 0; index < count; index++) {
- fThreadInfo[index].phase = aPhase;
- fThreadInfo[index].state = kAlive;
- if (index >= fThreadCount) {
- fThreadInfo[index].thread = new CBenchThread(&fThreadInfo[index]);
- fThreadCount++;
- fThreadInfo[index].thread->resume();
- }
- }
-
- for (index = fThreadCount; index > count; index--)
- fThreadInfo[index].state = kDie;
- #endif
-
- fPhase = aPhase;
- }
-
- void CStandApp::setState(const Boolean aState)
- {
- short index;
- short phase;
-
- if (aState == kStop) {
- #ifdef qNeoThreads
- killThreads();
- #endif
- phase = kNoPhase;
- }
- else {
- for (index = kMinPhase; index <= kMaxPhase; index++) {
- #if __MWERKS__
- fPhaseInfo[index].finished = FALSE;
- #endif
- fPhaseInfo[index].done = 0;
- fPhaseInfo[index].delta = 0;
- fPhaseInfo[index].committed = 0;
- fPhaseInfo[index].soFar = 0;
- }
-
- if (fPhaseInfo[kInsert].delta < fPhaseInfo[kInsert].target)
- phase = kMinPhase;
- else
- phase = kRandomly;
- }
- fState = aState;
-
- setPhase(phase);
- }
-
- /******************************************************************************
- spendTime
- ******************************************************************************/
- void CStandApp::doChores(void)
- {
- short index;
- long count;
- long loops = 0;
- CNeoDatabase * database = getDatabase();
- char string[20];
-
- NeoUsed(loops);
-
- if (fState == kStart) {
- #ifndef qNeoThreads
- TMTask timer;
-
- doSomeWork(fPhase, &timer);
- #endif
-
- for (index = kMinPhase; index <= kMaxPhase; index++) {
- #if __MWERKS__
- if (fPhaseInfo[index].finished)
- #endif
- if (fPhaseInfo[index].dirty) {
- #ifdef THINK_CPLUS
- cgotoxy(1, index +1, stdout);
- ccleol(stdout);
- #endif
- printf("%s -> ", PhaseName[index]);
- printf("Total = %6ld, ", (fPhaseInfo[index].delta + fPhaseInfo[index].done));
- getTime(fPhaseInfo[index].soFar / (fPhaseInfo[index].done ? fPhaseInfo[index].done : 1), string);
- count = (long)(((double)fPhaseInfo[index].committed / (double)(fPhaseInfo[index].soFar ? fPhaseInfo[index].soFar : 1)) * 1000000);
- printf("Obj./Sec. = %6ld, ", count);
- getTime(fPhaseInfo[index].soFar, string);
- printf("Total Time = %s", string);
- fPhaseInfo[index].dirty = FALSE;
- #if __MWERKS__
- printf("\n");
- fPhaseInfo[index].finished = FALSE;
- #endif
- }
- fRefresh = FALSE;
- }
- #if defined(THINK_CPLUS) || defined(__MWERKS__)
- fflush(stdout);
- #endif
-
- if (fPhase > kMaxPhase)
- setState(kStop);
-
- if (fPhase == kNoPhase &&
- database->isOpen())
- database->commit(TRUE);
- }
-
- #ifdef qNeoThreads
- loops = 0;
- while (!fRefresh) {
- CNeoThreadNative::Yield();
- #ifdef qNeoDebug
- loops++;
- if (loops > 1000) {
- loops = 0;
- break;
- }
- #endif
- }
- #endif
- }
-
- /******************************************************************************
- doSomeWork
- ******************************************************************************/
- void CStandApp::doSomeWork(const short aPhase, TMTask *aTimer)
- {
- long done;
- long IveDone = 0;
- long delta;
- long quantum;
- NeoID id;
- CNeoPersist * object;
- CNeoDatabase * oldDatabase = gNeoDatabase;
- CNeoDatabase * database = getDatabase();
- TMTask updateTask;
-
- #ifdef qNeoThreads
- quantum = 500 / fPhaseInfo[aPhase].threadCount;
- #else
- quantum = 500;
- #endif
- if (fPhaseInfo[aPhase].delta + fPhaseInfo[aPhase].done < fPhaseInfo[aPhase].target) {
- gNeoDatabase = database;
-
- updateTask.tmAddr = nil;
- updateTask.qType = 0;
- updateTask.tmCount = 0;
- updateTask.tmWakeUp = 0;
- updateTask.tmReserved = 0;
- InsXTime((QElem *)&updateTask);
- PrimeTime((QElem *)&updateTask, quantum);
-
- aTimer->tmAddr = nil;
- aTimer->qType = 0;
- aTimer->tmCount = 0;
- aTimer->tmWakeUp = 0;
- aTimer->tmReserved = 0;
- InsXTime((QElem *)aTimer);
- PrimeTime((QElem *)aTimer, k30MicroMinutes);
-
- while ((updateTask.qType&0x8000) &&
- (fPhaseInfo[aPhase].delta + fPhaseInfo[aPhase].done < fPhaseInfo[aPhase].target)) {
-
- fPhaseInfo[aPhase].done++;
- IveDone++;
-
- switch (aPhase) {
- case kInsert:
- /*------------------------------------------------------*/
- /* Perform the code for record insertion sequence */
- /*------------------------------------------------------*/
- object = new CFiller;
- FailNIL(object);
- delta = fPhaseInfo[kInsert].delta;
- done = fPhaseInfo[kInsert].done;
- object->fID = delta + done;
- database->addObject(object);
- object->unrefer();
- if (delta + done == fPhaseInfo[kInsert].target) {
- if (database->isOpen())
- database->commit(FALSE);
- }
- break;
-
- case kRandomly:
- /*------------------------------------------------------*/
- /* Perform the code for randomly searching sequence */
- /*------------------------------------------------------*/
- id = (rand()&0x7FFFFFFF) % fPhaseInfo[kInsert].target;
- if (!id)
- id = fPhaseInfo[kInsert].target / 2;
- object = (CFiller *)CFiller::FindByID(database, kFillerID, id, FALSE);
- NeoAssert(object);
- object->unrefer();
- break;
-
- case kSerially:
- /*------------------------------------------------------*/
- /* Serially iterate over a class of objects */
- /*------------------------------------------------------*/
- if (fIterator) {
- object = fIterator->nextObject();
- if (!object) {
- fIterator->reset();
- object = fIterator->currentObject();
- }
- }
- else {
- fIterator = new CNeoIndexIterator(database, kFillerID, nil, FALSE, FALSE);
- object = fIterator->currentObject();
- }
- NeoAssert(object);
- break;
-
- case kChange:
- /*------------------------------------------------------*/
- /* Perform the code for Change sequence here */
- /*------------------------------------------------------*/
- if (fIterator) {
- object = fIterator->nextObject();
- if (!object) {
- fIterator->reset();
- object = fIterator->currentObject();
- }
- }
- else {
- fIterator = new CNeoIndexIterator(database, kFillerID);
- object = fIterator->currentObject();
- }
- NeoAssert(object);
- object->autoReferTo();
- object->setDirty();
- object->autoUnrefer();
- database->setDirty();
- break;
-
- case kDelete:
- /*------------------------------------------------------*/
- /* Perform the code for Delete sequencing here */
- /*------------------------------------------------------*/
- if (!fIterator)
- fIterator = new CNeoIndexIterator(database, kFillerID);
- object = fIterator->currentObject();
- NeoAssert(object);
- object->autoReferTo();
- fIterator->removeCurrent();
- object->autoUnrefer();
- break;
- }
- }
-
- if (database->isOpen() &&
- database->isDirty() &&
- CNeoPersist::FCacheUsed > (CNeoPersist::FCacheSize>>1)) {
- database->commit(FALSE);
- setDirty(FALSE);
- }
-
- RmvTime((QElem *)aTimer);
- RmvTime((QElem *)&updateTask);
-
- if (aTimer->tmCount > 0)
- fPhaseInfo[aPhase].soFar += -(k30MicroMinutes + aTimer->tmCount * 1000) - gLoopOverhead;
- else
- fPhaseInfo[aPhase].soFar += -(k30MicroMinutes - aTimer->tmCount) - gLoopOverhead;
- fPhaseInfo[aPhase].committed += IveDone;
- fPhaseInfo[aPhase].dirty = TRUE;
-
- gNeoDatabase = oldDatabase;
- }
- else {
- #ifdef __MWERKS__
- fPhaseInfo[aPhase].finished = TRUE;
- #endif
- setPhase(aPhase +1);
- if (fIterator) {
- fIterator->setForward(!fIterator->isForward());
- fIterator->reset();
- }
- }
- }
-
- void CStandApp::exit(void)
- {
- }
-
- /****************************************************************************
- getTargetTotals - This method gets the target totals from the TextBoxes
- in the main dialog for each of the 5 phases. If there is any of the
- totals that are out of range, the text in the TextBoxes will be adjusted
- to be within range.
- *****************************************************************************/
- void CStandApp::getTargetTotals(void)
- {
- short index;
-
- for (index = kMinPhase; index <= kMaxPhase; index++)
- fPhaseInfo[index].target = default_vals[index];
- }
-
- /*********************************************************************
- aValue is microseconds of time.
-
- *********************************************************************/
- void CStandApp::getTime(long aValue, char *aString)
- {
- unsigned long value = (unsigned long)aValue;
- unsigned long thous = ((value % 1000000) / 100); // get thousandths of seconds
- unsigned long secs = ((value / 0x100000) % 60); // get seconds
- unsigned long mins = (value / (0x100000 * 60)); // get minutes
-
- sprintf(aString, "%2.0lu:%2.2lu.%4.4lu", mins, secs, thous);
- }
-
- #ifdef qNeoThreads
- void CStandApp::killThreads(void)
- {
- short index;
-
- for (index = 0; index < kMaxThreads; index++) {
- if (fThreadInfo[index].state == kAlive) {
- NeoAssert(fThreadInfo[index].thread);
- fThreadInfo[index].state = kDie;
- CNeoThreadNative::Yield(fThreadInfo[index].thread);
- fThreadInfo[index].thread = nil;
- }
- }
- }
- #endif
-
- #ifdef qNeoThreads
- CBenchThread::CBenchThread(ThreadInfo *aInfo, const NeoThreadType aType, void **aArg, const Size aStackSize, const NeoThreadOptions aOptions)
- : CNeoThreadNative(aType, aArg, aStackSize, aOptions)
- {
- fSetTimer = FALSE;
- fInfo = aInfo;
- }
-
- long CBenchThread::run(void)
- {
- while (fInfo->state == kAlive) {
- ((CStandApp *)gNeoApp)->doSomeWork(fInfo->phase, &fTimer);
-
- yield();
- }
-
- fInfo->thread = nil;
-
- return fResult;
- }
-
- // ---------------------------------------------------------------------------
- // • handleSwapIn
- // ---------------------------------------------------------------------------
- // Callback to the Thread Manager.
- //
- void CBenchThread::handleSwapIn(void)
- {
- inherited::handleSwapIn();
-
- // turn timers back on
- if (fSetTimer) {
- InsXTime((QElem *)&fTimer);
- PrimeTime((QElem *)&fTimer, 0);
- }
- }
-
- // ---------------------------------------------------------------------------
- // • handleSwapOut
- // ---------------------------------------------------------------------------
- // Callback to the Thread Manager.
- //
- void CBenchThread::handleSwapOut(void)
- {
- // turn timers off
- fSetTimer = fTimer.qType&0x8000;
- if (fSetTimer) {
- RmvTime((QElem *)&fTimer);
- fTimer.tmCount += gLoopOverhead;
- }
-
- inherited::handleSwapOut();
- }
-
- #endif
-
-